package camp

import (
	"github.com/pkg/errors"
	"math"
	"sync/atomic"
)

type Cmap interface {
	Put(key string,element interface{})(bool,error)
	Get(key string)interface{}
	Delete(key string)bool
	Concurrent()uint32
	Total()uint64
}
type camp struct {
	concurrent uint32
	segments [] Segment
	total uint64
}

func (this *camp)findSegment(hash uint64)Segment{
	if this.concurrent == 1{
		return this.segments[0]
	}
	var hash32 uint32
	if hash > math.MaxUint32{
		hash32 = uint32(hash >> 32)
	}else{
		hash32 = uint32(hash)
	}
	return this.segments[hash32%this.concurrent]
}
func (this *camp)Put(key string,element interface{})(bool,error)  {
	pair,err := New(key,element)
	if err != nil{
		return false,err
	}
	hash := pair.Hash()
	segment := this.findSegment(hash)
	ok,err := segment.Put(pair)
	if err != nil{
		return  false,err
	}
	if ok{
		atomic.AddUint64(&this.total,1)
	}
	return ok,err
}
func (this *camp)Get(key string)interface{}  {
	segment := this.findSegment(hash(key))
	 pair :=segment.Get(key)
	 if pair == nil{
	 	return nil
	 }
	 return pair.Element()
}
func (this *camp)Total()uint64  {
	return atomic.LoadUint64(&this.total)
}
func (this *camp)Concurrent()uint32  {
	return this.concurrent
}
func(this *camp) Delete(key string)bool  {
	segment := this.findSegment(hash(key))
	ok := segment.Delete(key)
	if ok{
		atomic.AddUint64(&this.total,^uint64(0))
	}
	return ok
}
func NewCamp(concrrent uint32)(Cmap,error){
	if concrrent == 0{
		return nil,errors.New("concurrent is must gt 0")
	}
	c := &camp{
		concurrent:concrrent,
	}
	c.segments = make([]Segment,concrrent)
	for i := 0;i<int(concrrent) ;i++  {
		c.segments[i] = NewSegment(0.75,1000)
	}
	return c,nil
}